
//
//  DemoLabel.swift
//  TextKit实现
//
//  Created by YYY on 2017/8/30.
//  Copyright © 2017年 成品家（北京）网路科技有限公司. All rights reserved.
//

import UIKit

class DemoLabel: UILabel {

    // MARK： TextKit的核心对象
    //文本属性存储
    fileprivate lazy var textStorage = NSTextStorage()
    
    //负责文本的字形布局
    fileprivate lazy var textLayoutManager = NSLayoutManager()
    
    //设定文本的绘制范围
    fileprivate lazy var textContainer = NSTextContainer()
    
    
    override var text: String?
    {
        didSet
        {
            prepareContent()
        }
    }
/*
     1:使用TextKit接管UILabel的底层实现
     2:使用正则表达式过滤URL
     3:交互
*/
    //构造函数
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        //准备文本系统
        prepareSystem()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        //准备文本系统
        prepareSystem()
        //fatalError("init(coder:) has not been implemented")
    }
    
    //响应用户操作事件
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        print("点我了")
        
        //获取用户点击的位置
        guard let location = touches.first?.location(in: self) else
        {
            return
        }
        //获取当前选中的字符索引
        
        let index = textLayoutManager.glyphIndex(for: location, in: textContainer)
        
        print("索引： \(index)")
        
        for range in urlRanges ?? []
        {
            if NSLocationInRange(index, range)
            {
                print("需要高亮")
                //修改文本字体颜色属性
                textStorage.addAttributes([NSForegroundColorAttributeName: UIColor.yellow], range: range)
                
                //如果需要重绘，调用setNeedsDisplay函数
                setNeedsDisplay()
            }
            else
            {
                print("不需要高亮")
            }
        }
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        //指定绘制的文本区域
        textContainer.size = bounds.size
    }
    
    //绘制文本
    //避免使用带有透明度的颜色，会严重影响性能
    //iOS中，绘制工作类似‘油画’，后绘制的内容，会把之前绘制的内容覆盖
    override func drawText(in rect: CGRect) {
        
        let range = NSRange(location: 0, length: textStorage.length)
        
        
        //绘制背景色
        textLayoutManager.drawBackground(forGlyphRange: range, at: CGPoint())
        //绘制字形
        textLayoutManager.drawGlyphs(forGlyphRange: range, at: CGPoint())
    }
}

private extension DemoLabel
{
    //准备文本系统
    func prepareSystem()
    {
        //开启用户交互
        isUserInteractionEnabled = true
        //准备文本内容
        prepareContent()
        
        //设置对象之间的关系
        textStorage.addLayoutManager(textLayoutManager)
        textLayoutManager.addTextContainer(textContainer)
    }
    
    //准备文本内容 textStorage接管label的内容
    func prepareContent()
    {
        if let attribute = attributedText {
            textStorage.setAttributedString(attribute)
        }
        else if let text = text
        {
            textStorage.setAttributedString(NSAttributedString(string: text))
        }
        else
        {
            textStorage.setAttributedString(NSAttributedString(string: ""))
        }
        
        for range in urlRanges ?? []
        {
            //[NSBackgroundColorAttributeName: UIColor.lightGray]
            textStorage.addAttributes([NSForegroundColorAttributeName: UIColor.blue], range: range)
            textStorage.addAttributes([NSBackgroundColorAttributeName: UIColor.init(white: 0.9, alpha: 1)], range: range)
        }
        //print(urlRanges)
    }
}

//正则表达式函数
private extension DemoLabel
{
    //计算型属性
    var urlRanges: [NSRange]?
    {
        //匹配项
        let pattern = "[a-zA-Z]*://[a-zA-Z0-9/\\.]*"
        
        guard let regx = try? NSRegularExpression(pattern: pattern, options: []) else
        {
            return nil
        }
        //多重匹配
        let result = regx.matches(in: textStorage.string, options: [], range: NSRange(location: 0, length: textStorage.length))
        
        var ranges: [NSRange] = [NSRange]()
        
        for match in result
        {
            let range = match.rangeAt(0)
            ranges.append(range)
        }
        return ranges
    }
    
}
